﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;

namespace YioksPlanEditor.Tools
{
    public class XmlTool
    {
        #region 反序列化
        /// <summary>
        /// 反序列化
        /// </summary>
        public static object Deserialize(Type type, XmlElement xml)
        {
            try
            {
                using (StringReader sr = new StringReader(xml.OuterXml))
                {
                    XmlSerializer xmldes = new XmlSerializer(type);
                    return xmldes.Deserialize(sr);
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
                return null;
            }
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        public static object Deserialize(Type type, XmlNode xml)
        {
            using (StringReader sr = new StringReader(xml.OuterXml))
            {
                XmlSerializer xmldes = new XmlSerializer(type);
                return xmldes.Deserialize(sr);
            }
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="xml">XML字符串</param>
        /// <returns></returns>
        public static object Deserialize(Type type, string xml)
        {
            try
            {
                using (StringReader sr = new StringReader(xml))
                {
                    XmlSerializer xmldes = new XmlSerializer(type);
                    return xmldes.Deserialize(sr);
                }
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="type"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static object Deserialize(Type type, Stream stream)
        {
            XmlSerializer xmldes = new XmlSerializer(type);
            return xmldes.Deserialize(stream);
        }
        #endregion

        #region 序列化
        /// <summary>
        /// 序列化
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static string Serializer(Type type, object obj)
        {
            MemoryStream stream = new MemoryStream();
            XmlSerializer xml = new XmlSerializer(type);
            //序列化对象
            xml.Serialize(stream, obj);
            stream.Position = 0;
            StreamReader sr = new StreamReader(stream);
            string str = sr.ReadToEnd();

            sr.Dispose();
            stream.Dispose();

            return str;
        }

        #endregion

        #region 反序列化部分场景对象
        public static List<T> GetElementInPlan<T>(XmlElement root, string nodeName, Dictionary<string, object> objs = null) where T : class
        {
            List<T> listObj = new List<T>();
            try
            {
                XmlNodeList passList = root.SelectNodes(nodeName);
                if (passList != null && passList.Count > 0)
                {
                    foreach (XmlNode skey in passList)
                    {
                        T obj = Deserialize(typeof(T), skey) as T;
                        if (obj != null)
                        {
                            //处理非子节点属性
                            ParseAttr(obj, skey);
                            PropertyInfo info = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.SetProperty |
                                                                        BindingFlags.Instance)
                                .FirstOrDefault(t => t.Name.Equals("_myid"));
                            if (info != null)
                            {
                                if (nodeName.Contains("/"))
                                {
                                    nodeName = nodeName.Substring(nodeName.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase) + 1);
                                }
                                string newId = nodeName + "_" + Guid.NewGuid();
                                if (info.GetValue(obj, null) == null || string.IsNullOrEmpty(info.GetValue(obj, null).ToString()))
                                {
                                    info.SetValue(obj, newId, null);
                                }
                                if (objs != null)
                                {
                                    objs.Add(newId, obj);
                                }
                            }

                            listObj.Add(obj);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            return listObj;
        }
        public static List<T> GetElementInSession<T>(XmlElement root, string nodeName, Dictionary<string, object> objs = null) where T : class
        {
            return GetElementInPlan<T>(root, "session/" + nodeName);

        }
        public static List<T> GetElementInScreen<T>(XmlElement root, string screenId, string nodeName) where T : class
        {
            List<T> listObj = new List<T>();
            try
            {
                XmlNodeList passList = root.SelectNodes("session/screen[_screenSortOrder=" + screenId + "]/" + nodeName);
                if (passList == null || passList.Count <= 0)
                {
                    passList = root.SelectNodes("session/screen[@_screenSortOrder=" + screenId + "]/" + nodeName);
                }
                if (passList != null && passList.Count > 0)
                {
                    foreach (XmlNode skey in passList)
                    {
                        T obj = Deserialize(typeof(T), skey) as T;
                        if (obj != null)
                        {
                            //处理非子节点属性
                            ParseAttr(obj, skey);
                            PropertyInfo info = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.SetProperty |
                                                                        BindingFlags.Instance)
                                .FirstOrDefault(t => t.Name.Equals("_myid"));
                            if (info != null)
                            {
                                string newId = nodeName + "_" + Guid.NewGuid();
                                if (info.GetValue(obj, null) == null || string.IsNullOrEmpty(info.GetValue(obj, null).ToString()))
                                {
                                    info.SetValue(obj, newId, null);
                                }
                            }

                            listObj.Add(obj);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            return listObj;
        }


        #endregion
        #region 反序列化属性扩展
        public static void ParseAttr(object parseObj, XmlNode xmlNode, bool overwrite = true)
        {
            if (parseObj != null)
            {
                if (xmlNode.Attributes != null && xmlNode.Attributes.Count > 0)
                {
                    PropertyInfo[] oldpropertys = parseObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.SetProperty |
                                   BindingFlags.Instance);
                    foreach (XmlAttribute xmlSessionAttribute in xmlNode.Attributes)
                    {

                        if (xmlSessionAttribute.Value == null) continue;
                        PropertyInfo info = oldpropertys.FirstOrDefault(t => t.Name.Equals(xmlSessionAttribute.Name));
                        if (info != null)
                        {
                            if (overwrite || info.GetValue(parseObj, null) == null)
                            {
                                info.SetValue(parseObj, xmlSessionAttribute.Value, null);
                            }
                        }

                    }
                }
            }
        }


        #endregion
    }
}
